package com.hxzy.config.interceptor;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.hxzy.common.constans.RedisConstans;
import com.hxzy.common.constans.WaimaiConst;
import com.hxzy.common.enums.AckCode;
import com.hxzy.common.exception.ServiceException;
import com.hxzy.common.util.TokenService;
import com.hxzy.common.util.WaimaiThreadLocal;
import com.hxzy.common.vo.resp.R;
import com.hxzy.controller.admin.login.resp.AdminLoginResp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Objects;

/**
 * @Desc 后台令牌有效性的验证
 * 1、验证请求头是否有令牌标识
 * 2、解析 jwt-->uuid
 * 3、uuid-->rediskey 查询
 * 4、查询结果缓存到本地线程池，供后面方法使用
 * 5、一个会话结束，移出本地线程池中的对象(弱引用数据类型)
 * @Author: admin
 * @Date: 2023/06/29/16:55
 */
@Component
public class AdminTokenInterceptor implements HandlerInterceptor {

    @Autowired
    private TokenService tokenService;

    /**
     * 执行controller之前的操作
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String jwtToken=request.getHeader(WaimaiConst.AUTORIZATION);
        //1、没有令牌，重新登录
        if(StrUtil.isBlank(jwtToken)){
            outJson(response,AckCode.APPLE_ILLEGAL);
           return false;
        }

        //如果token包含Bearer 就要删除
        if(jwtToken.startsWith("Bearer")){
            jwtToken=jwtToken.replace("Bearer","").trim();
        }

       //2、解析 jwt-->uuid
        String uuid = this.tokenService.jwtDecodeToUUID(jwtToken);

        //3、uuid-->rediskey 查询
        AdminLoginResp redisLoginVO = this.tokenService.getRedisLoginVO(uuid);

        //4、查询结果缓存到本地线程池，供后面方法使用
        if(Objects.isNull(redisLoginVO)){
            outJson(response,AckCode.APPLE_EXPIRED);
            return false;
        }

        //5、有时候可以对令牌进行续时(可选)
        //大
        Date expiredTime=redisLoginVO.getExpiredTime();
        //小
        Date now=new Date();
        // 过期时间-当前时间<=10分钟  ，续时
        if(expiredTime.getTime() - now.getTime()<= WaimaiConst.TEN_MINTUES) {
            this.tokenService.refreshToken(redisLoginVO);
        }

        WaimaiThreadLocal.loginVOThreadLocal.set(redisLoginVO);

        return true;
    }

    /**
     * 执行完Controller以后执行的操作
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //一个会话结束，移出本地线程池中的对象(弱引用数据类型)
        WaimaiThreadLocal.loginVOThreadLocal.remove();
    }

    private void outJson(HttpServletResponse response, AckCode ackCode) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        PrintWriter out=response.getWriter();

        String json= JSONUtil.toJsonStr( R.build(ackCode));
        out.println(json);
        out.flush();
        out.close();
    }

}
